package org.smarthings.coap;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapObserveRelation;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.smarthings.Callback;
import org.smarthings.Client;
import org.smarthings.Message;
import org.smarthings.Response;
import org.smarthings.Utils;

public class CoapClientImpl implements Client {
	private HashMap<String, CoapClient> clients = new HashMap<String, CoapClient>();
	private List<CoapObserveRelation> relations = new ArrayList<CoapObserveRelation>();
	private String host;
	private int port;

	public void start(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void stop() {
		for (CoapObserveRelation relation : relations) {
			relation.proactiveCancel();
		}
	}

	public String getProtocol() {
		return CoapFactory.PROTOCOL;
	}

	public Response post(Message message) {
		CoapClient client = getClient(message.getUri());
		int format = MediaTypeRegistry.parse(message.getContentType());
		CoapResponse response = client.post(message.getPayload(), format);
		return new Response(response.getPayload(), CoapUtil.getHttpCode(response));
	}

	public Message get(String resource, String contentType) {
		String uri = Utils.normalizeUri(resource);
		int accept = MediaTypeRegistry.parse(contentType);
		CoapClient client = getClient(uri);
		CoapResponse response = accept > 0 ? client.get(accept) : client.get();
		String format = MediaTypeRegistry.toString(response.getOptions().getContentFormat());
		return Message.createReciever(response.getPayload(), CoapFactory.PROTOCOL, uri, format,
				CoapUtil.getHttpCode(response));
	}

	public void subscribe(String resource, String contentType, Callback callback) {
		String uri = Utils.normalizeUri(resource);
		int accept = MediaTypeRegistry.parse(contentType);
		CoapClient client = getClient(uri);
		CoapObserveRelation relation = client.observe(new CoapHandlerImpl(uri, callback), accept);
		relations.add(relation);
	}

	private CoapClient getClient(String uri) {
		CoapClient client = clients.get(uri);
		if (client == null) {
			client = new CoapClient("coap://" + host + ":" + port + "/" + uri);
			clients.put(uri, client);
		}
		return client;
	}
}
